﻿using System;
using System.Collections.Generic;
using System.IO;
using NetTopologySuite.Features;
using NetTopologySuite.IO;
using NetTopologySuite.Geometries;
using Newtonsoft.Json;
using netDxf;
using netDxf.Entities;
using netDxf.Header;
using netDxf.Tables;
using netDxf.Units;

namespace ConsoleApp
{
    public class GeoJsonToCadConverter1
    {
        // 添加缩放因子和偏移量
        private const double ScaleFactor = 5000.0; // 放大倍数，根据实际情况调整
        private Vector2 _offset = Vector2.Zero;
        // 可以调整这两个参数：

        private double maxRange = 200 * ScaleFactor; // 增大边界范围
        private const double PointMarkerSize = 1.0;    // 点标记大小（米）
        private const double TextHeight = 2.5; // 文本高度（米）
        private const string DefaultIdField = "ID"; // 默认ID字段名

        public void Convert(string geoJsonFilePath, string outputDxfFilePath)
        {
            // 1. 读取GeoJSON文件
            var geoJson = File.ReadAllText(geoJsonFilePath);
            // 2. 解析GeoJSON为特征集合
            FeatureCollection features = ParseGeoJson(geoJson);
            // 3. 计算全局边界并确定偏移量
            CalculateOffset(features);
            // 4. 创建DXF文档
            var dxf = CreateDxfDocument();
            // 5. 创建图层
            var layers = CreateLayers(dxf);
            // 6. 转换所有特征
            ConvertAllFeatures(features, dxf, layers);
            // 7. 设置视图范围
            // 确保图形可见的最佳方法
            EnsureVisibleExtents(dxf);
            // 8. 保存DXF文件
            dxf.Save(outputDxfFilePath);
        }
        private FeatureCollection ParseGeoJson(string geoJson)
        {
            try
            {
                // 移除CRS部分
                var jsonObject = Newtonsoft.Json.Linq.JObject.Parse(geoJson);
                if(jsonObject.ContainsKey("crs"))
                {
                    jsonObject.Remove("crs");
                }
                if (jsonObject.ContainsKey("CRS"))
                {
                    jsonObject.Remove("CRS");
                }
                var reader = new GeoJsonReader();
                return reader.Read<FeatureCollection>(jsonObject.ToString());
            }
            catch (JsonException ex)
            {
                throw new InvalidOperationException("Invalid GeoJSON format", ex);
            }
        }
        private void CalculateOffset(FeatureCollection features)
        {
            var envelope = new Envelope();
            foreach (var feature in features)
            {
                envelope.ExpandToInclude(feature.Geometry.EnvelopeInternal);
            }
            // 计算缩放因子（保持原始比例）
            //_scaleFactor = TargetMetersPerUnit;
            _offset = new Vector2(-envelope.MinX, -envelope.MinY);
        }
        private DxfDocument CreateDxfDocument()
        {
            var dxf = new DxfDocument();
            dxf.DrawingVariables.InsUnits = DrawingUnits.Meters;
            return dxf;
        }
        private Dictionary<string, Layer> CreateLayers(DxfDocument dxf)
        {
            return new Dictionary<string, Layer>
            {
                { "Points", new Layer("Points") { Color = AciColor.Red } },
                { "Lines", new Layer("Lines") { Color = AciColor.Green } },
                { "Polygons", new Layer("Polygons") { Color = AciColor.Blue } },
                { "Text", new Layer("Text") { Color = AciColor.Cyan } },
                { "ID_Marks",  new Layer("ID_Marks") { Color = AciColor.Magenta } },
            };
        }
        private void ConvertAllFeatures(FeatureCollection features, DxfDocument dxf, Dictionary<string, Layer> layers)
        {
            foreach (var feature in features)
            {
                ConvertFeature(feature, dxf, layers);
            }
        }
        private void ConvertFeature(IFeature feature, DxfDocument dxf, Dictionary<string, Layer> layers)
        {
            var geometry = feature.Geometry;
            var attributes = feature.Attributes;
            // 转换几何图形
            switch (geometry.GeometryType)
            {
                case "Point":
                    ConvertPoint(geometry as NetTopologySuite.Geometries.Point, dxf, layers["Points"]);
                    break;
                case "LineString":
                    ConvertLineString(geometry as LineString, dxf, layers["Lines"]);
                    break;
                case "Polygon":
                    ConvertPolygon(geometry as Polygon, attributes, dxf, layers["Polygons"]);
                    break;
                case "MultiPoint":
                case "MultiLineString":
                case "MultiPolygon":
                    ConvertMultiGeometry(geometry as GeometryCollection, attributes, dxf, layers);
                    break;
                default:
                    Console.WriteLine($"Unsupported geometry type: {geometry.GeometryType}");
                    break;
            }

            // 添加文本标签
            if (attributes.Count > 0)
            {
                //AddTextLabel(feature, dxf, layers["Text"]);
            }
        }

        private void ConvertPoint(NetTopologySuite.Geometries.Point point, DxfDocument dxf, Layer pointLayer)
        {
            var (x, y) = ApplyTransform(point.X, point.Y);
            var dxfPoint = new netDxf.Entities.Point(new Vector2(x, y));
            dxfPoint.Layer = pointLayer;
            dxf.AddEntity(dxfPoint);

            // 添加点标记（小圆圈）
            //var circle = new Circle(new Vector2(x, y), PointMarkerSize / 2);
            //circle.Layer = pointLayer;
            //dxf.AddEntity(circle);
        }

        private void ConvertLineString(LineString lineString, DxfDocument dxf, Layer lineLayer)
        {
            var vertices = TransformCoordinates(lineString.Coordinates);
            var dxfLine = new Polyline(vertices, false);
            dxfLine.Layer = lineLayer;
            dxf.AddEntity(dxfLine);
        }

        private void ConvertPolygon(Polygon polygon, IAttributesTable attributes, DxfDocument dxf, Layer polygonLayer)
        {
            // 处理外环
            var exteriorVertices = TransformCoordinates(polygon.ExteriorRing.Coordinates);
            var dxfPolygon = new Polyline(exteriorVertices, true);
            dxfPolygon.Layer = polygonLayer;
            dxf.AddEntity(dxfPolygon);

            // 处理内环(孔洞)
            for (int i = 0; i < polygon.NumInteriorRings; i++)
            {
                var interiorVertices = TransformCoordinates(polygon.GetInteriorRingN(i).Coordinates);
                var dxfHole = new Polyline(interiorVertices, true);
                dxfHole.Layer = polygonLayer;
                dxf.AddEntity(dxfHole);
            }
            var id = GetFeatureId(attributes);
            // 在面中心添加ID文本
            var centroid = polygon.Centroid;
            var (x, y) = ApplyTransform(centroid.X, centroid.Y);
            //AddTextLabel(dxf, x, y, id, "ID_Marks");
            var idText = new Text($"{id}", new Vector2(x, y), 0.01)
            {
                Layer = new Layer("ID_Marks"),
                Color = AciColor.Magenta
            };
            dxf.AddEntity(idText);
        }

        private void ConvertMultiGeometry(GeometryCollection multiGeometry, IAttributesTable attributes,
            DxfDocument dxf, Dictionary<string, Layer> layers)
        {
            foreach (var subGeometry in multiGeometry.Geometries)
            {
                //var tempFeature = new Feature(subGeometry, attributes);
                var tempFeature = new Feature(subGeometry, attributes);
                ConvertFeature(tempFeature, dxf, layers);
            }
        }

        private Vector3[] TransformCoordinates(Coordinate[] coordinates)
        {
            var vertices = new Vector3[coordinates.Length];
            for (int i = 0; i < coordinates.Length; i++)
            {
                var (x, y) = ApplyTransform(coordinates[i].X, coordinates[i].Y);
                vertices[i] = new Vector3(x, y, 0);
            }
            return vertices;
        }

        private (double x, double y) ApplyTransform(double originalX, double originalY)
        {
            // 应用偏移和缩放
            var x = (originalX + _offset.X) * ScaleFactor;
            var y = (originalY + _offset.Y) * ScaleFactor;
            return (x, y);
        }

        private void EnsureVisibleExtents(DxfDocument dxf)
        {
            // 方法1：添加一个足够大的矩形作为参考范围
            var maxRange = 100 * ScaleFactor;
            var boundary = new Polyline(new[]
            {
                new Vector3(0, 0, 0),
                new Vector3(maxRange, 0, 0),
                new Vector3(maxRange, maxRange, 0),
                new Vector3(0, maxRange, 0)
            }, true)
            {
                Layer = new Layer("_BOUNDARY") { Color = AciColor.Cyan, IsVisible = false }
            };
            dxf.AddEntity(boundary);

            // 方法2：添加一个可见的点标记范围
            var centerMarker = new netDxf.Entities.Point(new Vector2(maxRange / 2, maxRange / 2))
            {
                Layer = new Layer("_CENTER") { Color = AciColor.Green }
            };
            dxf.AddEntity(centerMarker);

            // 方法3：替代视口设置的通用方法
            // 不再依赖特定版本的Viewports属性
            //AddViewportConfiguration(dxf, maxRange);
        }

        private void AddViewportConfiguration(DxfDocument dxf, double range)
        {
            try
            {
                // 通用方法：通过添加文本注释提示用户缩放
                var viewHint = new Text(
                    "请使用 ZOOM > EXTENTS 查看全部内容",
                    new Vector2(range / 2, range / 2 - 10),
                    2.0 * ScaleFactor)
                {
                    Layer = new Layer("_VIEWHINT") { Color = AciColor.Yellow }
                };
                dxf.AddEntity(viewHint);
            }
            catch
            {
                // 忽略版本兼容性问题
            }
        }

        private void AddTextLabel(DxfDocument dxf, double x, double y, string text, string layerName)
        {
            if (string.IsNullOrWhiteSpace(text)) return;

            var textEntity = new Text(text, new Vector2(x, y), TextHeight)
            {
                Layer = new Layer(layerName),
                Color = AciColor.Magenta,
                Alignment = TextAlignment.MiddleCenter
            };

            dxf.AddEntity(textEntity);
        }

        private string GetFeatureId(IFeature feature)
        {
            return GetFeatureId(feature.Attributes);
        }
        private string GetFeatureId(IAttributesTable attributes)
        {
            
            return attributes.Exists("DEVICE_ID") ? attributes["DEVICE_ID"].ToString() :
                    attributes.Exists("ID") ? attributes["ID"].ToString() :
                    Guid.NewGuid().ToString("N").Substring(0, 8);
        }
    }
}
